在用JSAPI开发微信支付的时候,遇到了很多坑,我也对朋友说过,一步一坑。最后终于算是走出来了。期间翻阅过很多网友写的教程,但是都不实用,JAVA,Python都有看过,大多数都是复制粘贴,倍感失望。
开发环境
thinkphp5.0
php
(开始使用JSAPI需要一个概念,就是在整个JSAPI的逻辑里面,只存在一个随机字符串
和一个 时间戳
。相当于JSAPI类里的全局。)
注意:由于我这里用的http_build_query()
body里面的中文会被格式化,所以这里先建议body使用非中文,至于中文解决,可以用正则去替换,或者不用http_build_query()
开始开发
全局初始化
public function __construct($total_fee, $body, $openid)
{
$rand = rand(11, 99);
$mp_info = get_mpid_info();//获取微信信息
$this->appid = $mp_info['appid'];
$this->nonce_str = nonceStr(32);
$this->spbill_create_ip = Request::instance()->ip();
$this->mch_id = $mp_info['mch_id'];
$this->key = $mp_info['paykey'];
$this->timestamp = time();
$this->sign;//一次签名
$this->total_fee = $total_fee;
$this->out_trade_no = time() . $rand;
$this->notify_url = 'http://uedream.cn/index.php';
$this->body = $body;
$this->openid = $openid;
$this->sign_type = 'MD5';
$this->createsign(); //生成签名方法,需要结合createsign方法
}
以上是初始化签名结构体
获取签名
文档:https://pay.weixin.qq.com/wik...
public function createsign()
{
$build = [
'appid' => $this->appid,
'body' => $this->body,
'mch_id' => $this->mch_id,
'nonce_str' => $this->nonce_str,
'notify_url' => $this->notify_url,
'openid' => $this->openid,
'out_trade_no' => $this->out_trade_no,
'sign_type' => $this->sign_type,
'spbill_create_ip' => $this->spbill_create_ip,
'timeStamp' => $this->timestamp,
'total_fee' => $this->total_fee,
'trade_type' => $this->trade_type,
'key' => $this->key,
];
$string = http_build_query($build);
$string = str_replace('%2F', '/', $string); //格式化网址
$string = str_replace('%3A', ':', $string); //格式化网址
$md5 = md5($string);
$this->sign = strtoupper($md5);
}
统一下单
文档:https://pay.weixin.qq.com/wik...
public function unifiedorder()
{
$data = [
'appid' => $this->appid,
'body' => $this->body,
'mch_id' => $this->mch_id,
'nonce_str' => $this->nonce_str,
'notify_url' => $this->notify_url,
'openid' => $this->openid,
'out_trade_no' => $this->out_trade_no,
'sign' => $this->sign,
'sign_type' => 'MD5',
'spbill_create_ip' => $this->spbill_create_ip,
'timeStamp' => $this->timestamp,
'total_fee' => $this->total_fee * 1,
'trade_type' => $this->trade_type,
];
$xml = arrayToXml($data);
$result = http_post(self::UNIFIEDORDER, $xml);
$return = xmlToArray($result);
$this->package = 'prepay_id=' . $return['prepay_id'];
$this->renCreatesign();//这是二次签名。文档里面我是没有看到,反正我是卡到这里了。
$returns = [
'appid' => $this->appid,
'noncestr' => $this->nonce_str,
'signtype' => $this->sign_type,
'package' => $this->package,
'sign' => $this->resign,
'timestamp' => $this->timestamp,
];
return $returns;
}
统一下单请忽略的所有的回调参数,只要prepay_id
,其它的参数暂时看做障眼法,获取到了统一下单,还需要进行二次签名,上面代码里面有一个$this->renCreatesign()
,就是调用的二次签名方法
二次签名
文档:https://pay.weixin.qq.com/wik...
所谓的二次签名就是,appId
,nonceStr
,package
,signType
,timeStamp
,key
的加密。一样的签名方式,可以参考签名文档,进行签名。(上面参数已经按照ASCII进行排序,大小写也请按照给出的进行加密)
注意: package
格式为prepay_id=xxxxxxxxxxxx
。xxxx部分为统一下单获取的prepay_id
代码参考:
public function renCreatesign()
{
$build_data = [
'appId' => $this->appid,
'nonceStr' => $this->nonce_str,
'package' => $this->package,
'signType' => $this->sign_type,
'timeStamp' => $this->timestamp,
'key' => $this->key,
];
$result = http_build_query($build_data);
$put_data = str_replace('%3D', '=', $result); //格式化网址
$signatrue = md5($put_data);
$this->resign = strtoupper($signatrue);
}
至此,所有的签名应经完成,控制器使用unifiedorder()
进行参数获取。
前端
这里开始使用jsapi做支付动作
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
appId: res.appid, //公众号名称,由商户传入
timeStamp: res.timeStamp, //时间戳,自1970年以来的秒数
nonceStr: res.nonce_str, //随机串
package: res.package,
signType: res.signType, //微信签名方式:
paySign: res.sign //微信签名
},
function(res) {
alert(JSON.stringify(res));
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
}
);
前端所有需要调用的参数均在unifiedorder()
可以获取到。
这里提一下WeixinJSBridge.invoke
与wx.chooseWXPay
的区别。WeixinJSBridge.invoke
可以不用引用weixinjs便可使用,也不需要config。在安卓手机上也能回调出错误信息。wx.chooseWXPay
需要引用weixinjs,也需要使用config,而且在安卓手机上面的提示特别不友好。
结语
微信支付文档说实话真的很坑 很坑。貌似写文档的小哥这天情绪不好。写出来的让人也感觉到了情绪不好。以上为本人切身操作写出的教程。如还有补充的地方可以随时留言评论。
彩蛋
文档:https://github.com/datalinkag...
下载地址:
composer require datalinkage/wxpay
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。